<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<link rel="stylesheet" type="text/css" href="../css/common.css" media="all" />
<link rel="stylesheet" type="text/css" href="../css/article.css" media="all" />
</head>
<body>
<div id="w3h_body">
  <div class="body_content">
    <!-- toc begin -->
    <h1 class="title">BX9026: 在 IE 的事件监听处理函数中使用 return false 语句依然可以阻止浏览器默认行为执行</h1>
        <ul class="toc">
      <li><a href="#standard_reference">标准参考</a> <span>•</span></li>
      <li><a href="#description">问题描述</a> <span>•</span></li>
      <li><a href="#influence">造成的影响</a> <span>•</span></li>
      <li><a href="#impacted_browsers">受影响的浏览器</a> <span>•</span></li>
      <li><a href="#analysis_of_issues">问题分析</a> <span>•</span></li>
      <li><a href="#solutions">解决方案</a> <span>•</span></li>
      <li><a href="#see_also">参见</a></li>
    </ul>
    <!-- toc end -->
    <div id="w3h_content">
      <!-- content begin -->
      <address class="author">作者：钱宝坤</address>
      <h2 id="standard_reference">标准参考</h2>
      <p>事件处理函数中的 return false 方法最初由 Netscape 制定，当时还没有事件监听注册方法，浏览器只支持为一个标记绑定一个事件处理函数，由此 Netscape 规定如果事件处理函数返回 false ，将就要阻止浏览器的默认事件行为继续执行，这个事实规范在所有浏览器中都被支持，它用于单一事件绑定函数中。</p>
      <p>在现行 DOM-Events 规范中已定义了 preventDefault 标准方法来阻止浏览器默认行为，该方法用来在事件监听处理程序中阻止浏览器默认事件触发。</p>
      <p>如经常使用的链接标记 A，用户点击他后浏览器将会根据 href 属性加载新的页面，这个默认行为是由点击一个链接事件引起的。但是，当该标签上还定义了一个 onclick 事件处理程序时，这个默认行为还被执行么？又是什么时候被执行的呢？这个问题显而易见，所有浏览器都会先执行 onclick 事件处理程序，而后再处理浏览器默认行为。此时，如果 onclick 事件处理程序返回值为 false，那么浏览器的默认行为将被阻止。这个在现看来是“约定俗成”的事实规范在所有浏览器中都被支持。</p>
      <p>关于取消事件的详细描述请参考 DOM-Level-2-Events 规范 <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow-cancelation">1.2.4. Event cancelation</a> </p>
      <p>关于 preventDefault 方法的描述请参考 DOM-Level-2-Events 规范 <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-Event">1.4. Event interface</a> </p>
      <h2 id="description">问题描述</h2>
      <p>古老的 return false 语句根据其历史使命应该仅对事件绑定函授处理方式生效，在事件监听处理程序中将不会阻止浏览器默认事件触发。</p>
      <p>但是在 IE 浏览器私有的事件处理模型和新支持的标准事件模型中，这个语句依然可以达到阻止浏览器默认事件触发的效果。</p>
      <h2 id="influence">造成的影响</h2>
      <p>在 IE 浏览器中，事件监听处理程序中的 return false 语句可以阻止浏览器默认行为继续执行，会导致超出作者预期的执行效果。</p>
      <h2 id="impacted_browsers">受影响的浏览器</h2>
      <table class="list">
              <tr>
                <th>IE6/7/8</th>
                <td></td>
              </tr>
            </table>
      <h2 id="analysis_of_issues">问题分析</h2>
      <h3>1、在事件绑定函数中使用 return false 语句阻止链接默认行为</h3>
      <p>分析以下代码：</p>
<pre>
&lt;a href="http://www.google.com/" onclick="return false"&gt;点击链接去 google ~~&lt;/a&gt;
</pre>

      <p>A 标记的 onclick 内联事件中执行了 return false 语句，他成功的阻止了浏览器加载 google.com 页面的默认行为，并且<strong>所有浏览器</strong>对此均处理一致。</p>
      <p>&nbsp;</p>
      <h3>2、在事件监听处理函数内使用 preventDefault 方法阻止链接默认行为</h3>
      <p>分析以下代码：</p>
<pre>
&lt;a href="http://www.google.com/"&gt;点击链接去 google ~~&lt;/a&gt;
&lt;script&gt;
  window.onload = function (){
    function stopDefault(e){
      e = e || window.event;
      (e.preventDefault)
      ?e.preventDefault()
      :e.returnValue = false;<sup>1</sup>
    }
    function addEvent(el, type, fn){
      (el.addEventListener)
      ? el.addEventListener(type, fn, false)
      : el.attachEvent("on" + type, fn);<sup>1</sup>

    }
    addEvent(document.getElementsByTagName("a")[0],"click",function (e){stopDefault(e)});
  }
&lt;/script&gt;
</pre>


      <p>上例中使用事件监听处理方法监听 A 标记的 click 事件，在具体处理函数内取消浏览器默认事件。</p>
      <p>这种方法也成功的阻止了浏览器加载 google.com 页面的默认行为，并且<strong>所有浏览器</strong>对此均处理一致。</p>
      <p class="comment">注1：IE 浏览器有其独有的事件处理模型，与 W3C 规范不同，此处优先判断并使用规范中的 preventDefault 方法，否则将使用 IE 事件模型 event. returnValue = false 语句来阻止浏览器默认行为。</p>
      <p class="comment">注2：IE 浏览器有其独有的事件监听处理模型，与 W3C 规范不同，此处优先判断并使用规范中的 addEventListener 方法，否则将使用 IE 的事件监听处理模型语句 attachEvent ，为元素添加事件处理函数。</p>
      <p class="comment">&nbsp;</p>
      <h3>3、在事件监听处理函数内的 return false 语句阻止链接默认行为</h3>
            <p>分析以下代码：</p>
<pre>
&lt;a href="http://www.google.com/"&gt;点击链接去 google ~~&lt;/a&gt;
&lt;script&gt;
  window.onload = function (){
    function addEvent(el, type, fn){
      (el.addEventListener)
      ? el.addEventListener(type, fn, false)
      : el.attachEvent("on" + type, fn);

    }
    addEvent(document.getElementsByTagName("a")[0],"click",function (){<span class="hl_4">return false</span>});
  }
&lt;/script&gt;
</pre>
          <p>本例中代码与例2大致相同，仅在事件处理函数中使用 return false 语句替换原始程序语句。</p>
          <p>不幸的是此程序执行后在各浏览器内明显存在差异，见下表：</p>
          <table class="compare">
            <tr>
              <th>IE6/7/8</th>
              <th>IE9 Firefox Safari Chrome Opera</th>
            </tr>
            <tr>
              <td>链接不跳转</td>
              <td>链接跳转到 Google</td>
            </tr>
          </table>
          <p>根据上表可以看出，IE6/7/8 浏览器中的 return false 语句在事件监听处理函数中依然可以阻止浏览器默认事件，而其他浏览器在此情况下只有明确的使用 preventDefault 方法才能达到相同效果。</p>
          <p>从 return false 语句的历史使命来看，他最初在单一事件绑定处理程序上生效，而 DOM-Events 中规定了标准事件处理模型，取消浏览器默认行为的语句为 preventDefault。 因此 return false 语句不应该会影响新的事件模型。<br />
      虽然 IE 使用了一套独立事件处理模型，可他仍有 e.returnValue = false 语句来达到与 return false 相同的功效，这与规范的事件模型定义有异曲同工之意， return false 语句也不应该影响他的事件模型。但是 IE6/7/8 并没有这么处理，由此可见，他对于 return false 这个古老的语句处理很有些守旧的味道。</p>
          <h2 id="solutions">解决方案</h2>
          <ul>
      <li>不要在<strong><em>事件监听</em></strong>处理函数内使用 return false 语句，在 IE6/7/8 中他会阻止浏览器默认行为执行；</li>
      <li>如果希望在<strong><em>事件绑定</em></strong>函数内取消浏览器默认行为，可以使用 return false 语句；</li>
      <li>如果希望在<strong><em>事件监听</em></strong>.处理函数内取消浏览器默认行为，可以使用 preventDefault 方法（IE 中需使用其私有的 event.returnValue = false 属性设置）。</li>
          </ul>
      <h2 id="see_also">参见</h2>
      <h3>知识库</h3>
      <ul class="see_also">
        <li><a href="#">...</a></li>
      </ul>

      <h3>相关问题</h3>
      <ul class="see_also">
        <li><a href="#">...</a></li>
      </ul>

<div class="appendix">
        <h2>测试环境</h2>
        <table class="list">
          <tr>
            <th>操作系统版本:</th>
            <td>Windows 7 Ultimate build 7600</td>
          </tr>
          <tr>
            <th>浏览器版本:</th>
            <td>
              IE6<br />
              IE7<br />
              IE8<br />
              Firefox 3.6.8<br />
              Chrome 7.0.503.0 dev<br />
              Safari 5.0.1 <br />
                            Opera 10.61
            </td>
          </tr>
          <tr>
            <th>测试页面:</th>
            <td><a href="../../tests/BX9026/prevent_browser_default_behavior.html">prevent_browser_default_behavior.html</a></td>
          </tr>
          <tr>
            <th>本文更新时间:</th>
            <td>2010-09-08</td>
          </tr>
        </table>

        <h2>关键字</h2>  
        <!-- keywords begin -->
        <p>preventDefault returnValue Browser Befault Behavior  </p>
        <!-- keywords end -->
      </div>
      <!-- content end -->
    </div>
  </div>
</div>
</body>
</html>
